﻿using System;
using System.Runtime.InteropServices;
using System.Threading;
using MyNes.Core;
using SDL2;
namespace audiotest
{
    class Program
    {
        static ushort buffersize = 1024 * 5;
        static byte[] audiobuf = new byte[buffersize * 20];
        static int audioreadpos = 0;
        static int audiowritepos = 0;
        static int samples_added = 0;
        static void Main(string[] args)
        {

            Console.WriteLine("Hello World!");

            //audio test
            var result = SDL.SDL_Init(SDL.SDL_INIT_AUDIO);
            Console.WriteLine("init sdl audio=" + result);

            SDL.SDL_AudioSpec wanted_spec = new SDL.SDL_AudioSpec();
            wanted_spec.freq = 48000;
            wanted_spec.format = SDL.AUDIO_S16SYS;//根据系统决定合适的字节序
            wanted_spec.channels = 1;
            wanted_spec.silence = 0;
            wanted_spec.samples = buffersize;
            wanted_spec.callback = SDL_AudioCallback;
            try
            {
                var resultopen = SDL.SDL_OpenAudio(ref wanted_spec, IntPtr.Zero);
                Console.WriteLine("open sdl audio=" + resultopen);
                if (resultopen < 0)
                {
                    var strerr = SDL.SDL_GetError();
                    Console.WriteLine("open sdl audio=" + strerr);

                }
                SDL.SDL_PauseAudio(0);
            }
            catch (Exception err)
            {
                return;
            }
            Controller con = new Controller();

            var window = SDLTool.CreateNESWindow("hi window", 512, 480);
            window.surfaceNES = SDLTool.CreateNesTargetSurface();
            window.UpdateWindow();

            window.eventOnKey += (key, press) =>
            {
                switch (key.scancode)
                {
                    case SDL.SDL_Scancode.SDL_SCANCODE_W:
                        con.bUp = press;
                        break;
                    case SDL.SDL_Scancode.SDL_SCANCODE_A:
                        con.bLeft = press;
                        break;
                    case SDL.SDL_Scancode.SDL_SCANCODE_S:
                        con.bDown = press;
                        break;
                    case SDL.SDL_Scancode.SDL_SCANCODE_D:
                        con.bRight = press;
                        break;
                    case SDL.SDL_Scancode.SDL_SCANCODE_J:
                        con.bBtnB = press;
                        break;
                    case SDL.SDL_Scancode.SDL_SCANCODE_K:
                        con.bBtnA = press;
                        break;
                    case SDL.SDL_Scancode.SDL_SCANCODE_O:
                        con.bBtnSelect = press;
                        break;
                    case SDL.SDL_Scancode.SDL_SCANCODE_P:
                        con.bBtnStart = press;
                        break;
                }
            };
            MyNes.Core.MyNesMain.Light_Init();
            byte[] data = new byte[256 * 240];

            NesEmu.SetupControllersP1(con);
            int fcount = 0;
            DateTime begin = DateTime.Now;
            MyNes.Core.NesEmu.Light_SetupVideoRender((ref int[] datas) =>
            {

                window.surfaceNES.SetPixels(datas, 256, 240);
                fcount++;
                if (fcount > 120)
                {
                    DateTime now = DateTime.Now;
                    var delay = (now - begin).TotalSeconds;
                    var fps = fcount / delay;
                    begin = now;
                    fcount = 0;
                    Console.WriteLine("fps=" + fps);
                }
            });
            MyNes.Core.NesEmu.LoadGame("2.nes", out bool success, true);

            MyNes.Core.NesEmu.Light_SetupAudioSamples((ref short[] buffer, ref int samples_count) =>
            {
                var buflen = audiobuf.Length;
                for (var i = 0; i < samples_count; i++)
                {
                    var sample = (short)(buffer[i] * 0.5f);
                    //var sb = BitConverter.GetBytes(sample);
                    var hb = (byte)(sample >> 8); ;
                    var lb = (byte)(sample & 0xFF);
                    //明明说是小頭順序，这里sample 的 高位 为什么放在前面？
                    //这不是和系统顺序反了吗
                    if (BitConverter.IsLittleEndian)
                    {
                        audiobuf[audiowritepos++ % buflen] = hb;
                        audiobuf[audiowritepos++ % buflen] = lb;
                    }
                    else
                    {
                        audiobuf[audiowritepos++ % buflen] = lb;
                        audiobuf[audiowritepos++ % buflen] = hb;
                    }
                    samples_added++;
                }
            });


            SDLTool.SDLMainLoop();

        }

        class Controller : MyNes.Core.IJoypadConnecter
        {
            public bool bLeft;
            public bool bUp;
            public bool bRight;
            public bool bDown;
            public bool bBtnA;
            public bool bBtnB;
            public bool bBtnSelect;
            public bool bBtnStart;
            public override void Update()
            {
                var tagright = (bRight ? 1 : 0) << 7; //right
                var tagleft = (bLeft ? 1 : 0) << 6;//left
                var tagdown = (bDown ? 1 : 0) << 5;
                var tagup = (bUp ? 1 : 0) << 4;
                var tagStart = (bBtnStart ? 1 : 0) << 3; //sure
                var tagSel = (bBtnSelect ? 1 : 0) << 2;
                var tagB = (bBtnB ? 1 : 0) << 1;
                var tagA = (bBtnA ? 1 : 0) << 0;
                this.DATA = (byte)(tagleft | tagup | tagdown | tagright | tagA | tagB | tagSel | tagStart);
            }
        }
        static bool start = false;


        static unsafe void SDL_AudioCallback(IntPtr userdata, IntPtr stream, int len)
        {
            if (!start)
            {
                if (samples_added > 3000)
                    start = true;
                return;
            }
            var buflen = audiobuf.Length;
            byte* data = (byte*)stream;
            for (var i = 0; i < len; i += 2)
            {
                if (samples_added > 0)
                {
                    data[i] = audiobuf[audioreadpos++ % buflen];
                    data[i + 1] = audiobuf[audioreadpos++ % buflen];
                    samples_added--;
                }
            }
        }

    }
}
